#!/bin/bash
# 主构建脚本
# Main Build Script for Protocol Library

# 脚本目录
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
PROJECT_ROOT="$SCRIPT_DIR"
cd "$PROJECT_ROOT" || exit

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
GRAY='\033[0;37m'
NC='\033[0m' # No Color

# 日志级别
LOG_LEVEL_ERROR=0
LOG_LEVEL_WARNING=1
LOG_LEVEL_INFO=2
LOG_LEVEL_DEBUG=3
LOG_LEVEL_TRACE=4

# 当前日志级别（默认INFO）
CURRENT_LOG_LEVEL=${LOG_LEVEL_INFO}

# 交互式菜单变量
CURRENT_SELECTION=0
MENU_ITEMS=()
MENU_TITLE=""

# 日志统计
LOG_STATS_ERROR=0
LOG_STATS_WARNING=0
LOG_STATS_INFO=0
LOG_STATS_DEBUG=0
LOG_STATS_TRACE=0

# 日志打印函数
print_error() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_ERROR ]; then
        echo -e "${RED}[ERROR]${NC} $1"
        LOG_STATS_ERROR=$((LOG_STATS_ERROR + 1))
    fi
}

print_warning() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_WARNING ]; then
        echo -e "${YELLOW}[WARNING]${NC} $1"
        LOG_STATS_WARNING=$((LOG_STATS_WARNING + 1))
    fi
}

print_info() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_INFO ]; then
    echo -e "${BLUE}[INFO]${NC} $1"
        LOG_STATS_INFO=$((LOG_STATS_INFO + 1))
    fi
}

print_debug() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_DEBUG ]; then
        echo -e "${CYAN}[DEBUG]${NC} $1"
        LOG_STATS_DEBUG=$((LOG_STATS_DEBUG + 1))
    fi
}

print_trace() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_TRACE ]; then
        echo -e "${GRAY}[TRACE]${NC} $1"
        LOG_STATS_TRACE=$((LOG_STATS_TRACE + 1))
    fi
}

print_success() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_INFO ]; then
    echo -e "${GREEN}[SUCCESS]${NC} $1"
    fi
}

print_header() {
    echo -e "${PURPLE}================================${NC}"
    echo -e "${PURPLE}  $1${NC}"
    echo -e "${PURPLE}================================${NC}"
}

# 函数调用日志
log_function_entry() {
    local func_name="$1"
    shift
    local params="$*"
    print_debug "→ 进入函数: $func_name"
    if [ -n "$params" ]; then
        print_debug "  参数: $params"
    fi
}

log_function_exit() {
    local func_name="$1"
    local exit_code="${2:-0}"
    if [ "$exit_code" -eq 0 ]; then
        print_debug "← 退出函数: $func_name (成功)"
    else
        print_debug "← 退出函数: $func_name (失败, 退出码: $exit_code)"
    fi
}

# 命令执行日志
log_command() {
    local cmd="$*"
    print_debug "执行命令: $cmd"
}

log_command_result() {
    local exit_code="$1"
    if [ "$exit_code" -eq 0 ]; then
        print_debug "命令执行成功"
    else
        print_error "命令执行失败，退出码: $exit_code"
    fi
}

# 文件操作日志
log_file_operation() {
    local operation="$1"
    local file_path="$2"
    print_debug "文件操作: $operation -> $file_path"
}

# 目录操作日志
log_directory_operation() {
    local operation="$1"
    local dir_path="$2"
    print_debug "目录操作: $operation -> $dir_path"
}

# 显示日志统计
show_log_stats() {
    if [ $CURRENT_LOG_LEVEL -ge $LOG_LEVEL_DEBUG ]; then
        print_debug "=== 日志统计 ==="
        print_debug "ERROR:   $LOG_STATS_ERROR"
        print_debug "WARNING: $LOG_STATS_WARNING"
        print_debug "INFO:    $LOG_STATS_INFO"
        print_debug "DEBUG:   $LOG_STATS_DEBUG"
        print_debug "TRACE:   $LOG_STATS_TRACE"
    fi
}

# 设置日志级别
set_log_level() {
    local level="$1"
    case "$level" in
        "error"|"ERROR"|"0")
            CURRENT_LOG_LEVEL=$LOG_LEVEL_ERROR
            print_info "日志级别设置为: ERROR"
            ;;
        "warning"|"WARNING"|"1")
            CURRENT_LOG_LEVEL=$LOG_LEVEL_WARNING
            print_info "日志级别设置为: WARNING"
            ;;
        "info"|"INFO"|"2")
            CURRENT_LOG_LEVEL=$LOG_LEVEL_INFO
            print_info "日志级别设置为: INFO"
            ;;
        "debug"|"DEBUG"|"3")
            CURRENT_LOG_LEVEL=$LOG_LEVEL_DEBUG
            print_info "日志级别设置为: DEBUG"
            ;;
        "trace"|"TRACE"|"4")
            CURRENT_LOG_LEVEL=$LOG_LEVEL_TRACE
            print_info "日志级别设置为: TRACE"
            ;;
        *)
            print_error "无效的日志级别: $level"
            print_info "可用级别: error, warning, info, debug, trace"
            return 1
            ;;
    esac
}

# 获取当前日志级别名称
get_log_level_name() {
    case $CURRENT_LOG_LEVEL in
        $LOG_LEVEL_ERROR) echo "ERROR" ;;
        $LOG_LEVEL_WARNING) echo "WARNING" ;;
        $LOG_LEVEL_INFO) echo "INFO" ;;
        $LOG_LEVEL_DEBUG) echo "DEBUG" ;;
        $LOG_LEVEL_TRACE) echo "TRACE" ;;
        *) echo "UNKNOWN" ;;
    esac
}

# 清屏
clear_screen() {
    clear
}

# 显示菜单
show_menu() {
    local title="$1"
    shift
    MENU_ITEMS=("$@")
    MENU_TITLE="$title"
    
    clear_screen
    print_header "$title"
    echo ""
    
    for i in "${!MENU_ITEMS[@]}"; do
        if [ $i -eq $CURRENT_SELECTION ]; then
            echo -e "${WHITE}▶ ${MENU_ITEMS[$i]}${NC}"
        else
            echo -e "  ${MENU_ITEMS[$i]}"
        fi
    done
    
    echo ""
    echo -e "${CYAN}使用 ↑↓ 键选择，回车确认，q 退出${NC}"
}

# 处理键盘输入
handle_input() {
    while true; do
        read -rsn1 key
        
        case $key in
            $'\x1b')  # ESC sequence
                read -rsn2 key
                case $key in
                    '[A')  # Up arrow
                        if [ $CURRENT_SELECTION -gt 0 ]; then
                            ((CURRENT_SELECTION--))
                        fi
                        show_menu "$MENU_TITLE" "${MENU_ITEMS[@]}"
                        ;;
                    '[B')  # Down arrow
                        if [ $CURRENT_SELECTION -lt $((${#MENU_ITEMS[@]} - 1)) ]; then
                            ((CURRENT_SELECTION++))
                        fi
                        show_menu "$MENU_TITLE" "${MENU_ITEMS[@]}"
                        ;;
                esac
                ;;
            '')  # Enter
                return $CURRENT_SELECTION
                ;;
            'q'|'Q')  # Quit
                return -1
                ;;
        esac
    done
}

# 等待按键
wait_for_key() {
    echo ""
    echo -e "${CYAN}按任意键继续...${NC}"
    read -n 1 -s
}

# 显示帮助信息
show_help() {
    echo "协议库构建脚本"
    echo ""
    echo "用法: $0 [命令]"
    echo ""
    echo "命令:"
    echo "  set                        设置配置（交互式选择协议、构建类型、版本）"
    echo "  build                      根据配置直接构建项目"
    echo "  interactive                交互式菜单模式"
    echo "  clean                      清理构建文件"
    echo "  help, -h, --help           显示此帮助信息"
    echo ""
    echo "日志级别:"
    echo "  debug                      启用DEBUG级别日志（详细执行信息）"
    echo "  trace                      启用TRACE级别日志（最详细信息）"
    echo ""
    echo "使用流程:"
    echo "  1. $0 set                  首次使用，设置配置"
    echo "  2. $0 build                根据配置构建项目"
    echo "  4. $0 clean                清理构建文件"
    echo ""
    echo "配置选项:"
    echo "  协议类型: 104协议"
    echo "  构建类型: 全量编译、只编译协议"
    echo "  版本类型: 测试版本、调试版本、正式版本"
    echo ""
    echo "示例:"
    echo "  $0 set                     设置配置"
    echo "  $0 build                   执行构建"
    echo "  $0 debug build             启用DEBUG日志执行构建"
    echo "  $0 clean                   清理构建文件"
}


# 协议选择菜单
protocol_menu() {
    CURRENT_SELECTION=0
    show_menu "选择协议类型" "104协议" "返回主菜单"
    handle_input
    local choice=$?
    
    case $choice in
        0)  # 104协议
            protocol_104_menu
            ;;
        1)  # 返回主菜单
            return 0
            ;;
        -1)  # 退出
            exit 0
            ;;
    esac
}

# 104协议子菜单
protocol_104_menu() {
    CURRENT_SELECTION=0
    show_menu "104协议构建选项" "全量编译" "只编译协议" "返回上级"
    handle_input
    local choice=$?
    
    case $choice in
        0)  # 全量编译
            protocol_104_version_menu "full"
            ;;
        1)  # 只编译协议
            protocol_104_version_menu "protocol"
            ;;
        2)  # 返回上级
            protocol_menu
            ;;
        -1)  # 退出
            exit 0
            ;;
    esac
}

# 104协议版本选择菜单
protocol_104_version_menu() {
    local build_type="$1"
    CURRENT_SELECTION=0
    show_menu "选择构建版本" "测试版本" "调试版本" "正式版本" "返回上级"
    handle_input
    local choice=$?
    
    case $choice in
        0)  # 测试版本
            protocol_104_execute_build "$build_type" "test"
            ;;
        1)  # 调试版本
            protocol_104_execute_build "$build_type" "debug"
            ;;
        2)  # 正式版本
            protocol_104_execute_build "$build_type" "release"
            ;;
        3)  # 返回上级
            protocol_104_menu
            ;;
        -1)  # 退出
            exit 0
            ;;
    esac
}

# 执行104协议构建
protocol_104_execute_build() {
    local build_type="$1"
    local version="$2"
    
    # 更新配置文件中的版本
    update_config_version "$version"
    
    case $build_type in
        "full")
            print_header "104协议全量编译 - $version版本"
            do_build
            ;;
        "protocol")
            print_header "104协议编译 - $version版本"
            do_build
            ;;
    esac
    
    show_build_results
    wait_for_key
}

# 更新配置文件版本
update_config_version() {
    local version="$1"
    
    if [ -f "config/project.conf" ]; then
        # 备份原配置
        cp "config/project.conf" "config/project.conf.bak"
        
        # 更新版本
        sed -i.tmp "s/VERSION=.*/VERSION=$version/" "config/project.conf"
        rm -f "config/project.conf.tmp"
        
        print_info "已更新配置为 $version 版本"
    else
        print_warning "配置文件不存在，将创建新配置"
        create_config_file "$version"
    fi
}

# 创建配置文件
create_config_file() {
    local protocol="$1"
    local build_type="$2"
    local version="$3"
    
    mkdir -p config
    cat > "config/project.conf" << EOF
PROTOCOL=$protocol
BUILD_TYPE=$build_type
VERSION=$version
VERSION_MAJOR=1
VERSION_MINOR=0
VERSION_PATCH=0

# 版本生成相关配置
PROJECT_NAME="DLSYSTEM-PROTOCOL-104"
PROTOCOL_TYPE="104"
PROTOCOL_DESCRIPTION="IEC 60870-5-104 Protocol Implementation"
PROJECT_AUTHOR="DLSYSTEM Team"
TIMESTAMP_FORMAT="%Y%m%d%H%M"
VERSION_FORMAT="{PROJECT_NAME} v{PROJECT_VERSION}-{BUILD_VERSION}-{TIMESTAMP}"
BUILD_INFO_TEMPLATE="{PROTOCOL_TYPE} Protocol v{PROJECT_VERSION}-{BUILD_VERSION} built on {BUILD_DATE} {BUILD_TIME}"
DEFAULT_BUILD_VERSION="test"
EOF
    
    print_info "已创建配置文件: config/project.conf"
    print_info "  协议: $protocol"
    print_info "  构建类型: $build_type"
    print_info "  版本: $version"
}


# 显示构建结果
show_build_results() {
    print_header "构建结果"
    
    echo -e "${CYAN}输出目录结构:${NC}"
    if [ -d "output/104" ]; then
        tree output/104/ 2>/dev/null || find output/104/ -type f | sort
    else
        print_warning "output/104目录不存在"
    fi
    
    echo ""
    echo -e "${CYAN}可执行文件:${NC}"
    
    echo ""
    echo -e "${CYAN}库文件:${NC}"
    if [ -d "output/104/lib" ]; then
        for lib in output/104/lib/*.a; do
            if [ -f "$lib" ]; then
                echo -e "  ${GREEN}✓${NC} $(basename $lib)"
            fi
        done
    else
        echo -e "  ${RED}✗${NC} 库文件目录不存在"
    fi
}


# 主菜单
main_menu() {
    while true; do
        CURRENT_SELECTION=0
        show_menu "104协议项目构建菜单" "选择协议" "清理构建" "显示构建结果" "退出"
        handle_input
        local choice=$?
        
        case $choice in
            0)  # 选择协议
                protocol_menu
                ;;
            1)  # 清理构建
                clean_build
                wait_for_key
                ;;
            2)  # 显示构建结果
                show_build_results
                wait_for_key
                ;;
            3)  # 退出
                print_info "退出构建脚本"
                exit 0
                ;;
            -1)  # 退出
                exit 0
                ;;
        esac
    done
}

# 创建统一静态库
create_unified_library() {
    local protocol=$1
    local unified_lib="output/lib/libprotocol104.a"
    
    print_info "创建统一静态库..."
    
    # 创建临时目录
    local temp_dir=$(mktemp -d)
    
    # 确保协议库已构建
    if [ ! -f "output/$protocol/lib/libprotocol104.a" ]; then
        print_info "协议库不存在，从app目录构建..."
        cd "core/$protocol" && make debug > /dev/null 2>&1 && cd "$PROJECT_ROOT"
    fi
    
    # 收集所有目标文件
    print_info "收集所有目标文件..."
    
    # 协议相关目标文件
    if [ -d "output/$protocol/obj" ]; then
        find "output/$protocol/obj" -name "*.o" -exec cp {} "$temp_dir/" \;
    fi
    
    # 通用模块目标文件
    if [ -d "output/obj" ]; then
        find "output/obj" -name "*.o" -exec cp {} "$temp_dir/" \;
    fi
    
    # 传输模块目标文件
    if [ -d "output/transport/obj" ]; then
        find "output/transport/obj" -name "*.o" -exec cp {} "$temp_dir/" \;
    fi
    
    # 创建统一静态库
    if [ "$(ls -A "$temp_dir" 2>/dev/null)" ]; then
        cd "$temp_dir" && ar rcs "$PROJECT_ROOT/$unified_lib" *.o && cd "$PROJECT_ROOT"
        print_info "✅ 统一静态库创建完成: $unified_lib"
    else
        print_error "❌ 没有找到目标文件"
        rm -rf "$temp_dir"
        return 1
    fi
    
    # 清理临时目录
    rm -rf "$temp_dir"
}

# 整理输出文件
organize_output_files() {
    local protocol=$1
    local version=$2
    
    print_info "   📚 创建统一静态库..."
    # 创建统一的静态库
    create_unified_library "$protocol"
    print_info "      ✅ 统一静态库创建完成"
    
    # 只复制必要的头文件，隐藏内部实现
    # 用户只需要主头文件 protocol104.h，其他头文件不暴露
    
    print_info "   📄 创建主头文件..."
    # 创建主头文件
    create_main_header "$protocol" "$version"
    print_info "      ✅ 主头文件创建完成"
}

# 创建主头文件
create_main_header() {
    local protocol=$1
    local version=$2
    
    # 确保在项目根目录
    cd "$PROJECT_ROOT" || return 1
    
    # 创建必要的目录
    mkdir -p "output/$protocol/include"
    
    local main_header="output/$protocol/include/protocol104.h"
    
    cat > "$main_header" << EOF
/**
 * @file protocol104.h
 * @brief 104协议库用户接口
 * @details 提供简洁的104协议使用接口，用户只需关心数据发送和接收
 * 
 * @author zyb
 * @date $(date +%Y-%m-%d)
 * @version $version
 */

#ifndef PROTOCOL104_H
#define PROTOCOL104_H

#ifdef __cplusplus
extern "C" {
#endif

/* 基础类型定义 */
#include <stdint.h>
#include <stdbool.h>

/* 数据类型枚举 */
typedef enum {
    DATA_TYPE_SINGLE_POINT = 1,      // 单点信息
    DATA_TYPE_DOUBLE_POINT = 3,      // 双点信息
    DATA_TYPE_MEASUREMENT = 9,       // 测量值
    DATA_TYPE_SINGLE_COMMAND = 45,   // 单命令
    DATA_TYPE_DOUBLE_COMMAND = 46,   // 双命令
    DATA_TYPE_CLOCK_SYNC = 103,      // 时钟同步
    DATA_TYPE_INTERROGATION = 100    // 总召唤
} data_type_t;

/* 数据质量 */
typedef enum {
    DATA_QUALITY_GOOD = 0,
    DATA_QUALITY_UNCERTAIN = 1,
    DATA_QUALITY_BAD = 2,
    DATA_QUALITY_INVALID = 3
} data_quality_t;

/* 发送结果 */
typedef enum {
    SEND_RESULT_SUCCESS = 0,         // 发送成功
    SEND_RESULT_FAILED = 1,          // 发送失败
    SEND_RESULT_TIMEOUT = 2,         // 发送超时
    SEND_RESULT_DISCONNECTED = 3,    // 连接断开
    SEND_RESULT_INVALID_DATA = 4     // 数据无效
} send_result_t;

/* 通用数据点结构 */
typedef struct {
    uint32_t address;           // 信息对象地址
    data_type_t type;          // 数据类型
    data_quality_t quality;    // 数据质量
    uint64_t timestamp;        // 时间戳（毫秒）
    union {
        bool single_point;     // 单点值
        uint8_t double_point;  // 双点值 (0=中间态, 1=分, 2=合)
        float measurement;     // 测量值
        bool single_command;   // 单命令
        uint8_t double_command; // 双命令
    } value;
} protocol_data_t;

/* 协议句柄 */
typedef void* protocol_handle_t;

/* 回调函数类型 */
typedef void (*protocol_data_callback_t)(const protocol_data_t* data, void* user_data);
typedef void (*protocol_send_result_callback_t)(send_result_t result, const char* message, void* user_data);

/* 协议配置 */
typedef struct {
    const char* server_ip;             // 服务器IP
    uint16_t server_port;              // 服务器端口
    uint32_t common_address;           // 公共地址
    uint32_t timeout_ms;               // 超时时间（毫秒）
    bool auto_reconnect;               // 自动重连
} protocol_config_t;

/* 用户接口函数 */

/**
 * @brief 创建协议实例
 * @param config 协议配置
 * @return 协议句柄，失败返回NULL
 */
protocol_handle_t protocol_create(const protocol_config_t* config);

/**
 * @brief 销毁协议实例
 * @param handle 协议句柄
 */
void protocol_destroy(protocol_handle_t handle);

/**
 * @brief 连接服务器
 * @param handle 协议句柄
 * @return 0成功，非0失败
 */
int protocol_connect(protocol_handle_t handle);

/**
 * @brief 断开连接
 * @param handle 协议句柄
 */
void protocol_disconnect(protocol_handle_t handle);

/**
 * @brief 发送数据
 * @param handle 协议句柄
 * @param data 要发送的数据
 * @return 发送结果
 */
send_result_t protocol_send_data(protocol_handle_t handle, const protocol_data_t* data);

/**
 * @brief 注册数据接收回调
 * @param handle 协议句柄
 * @param callback 数据回调函数
 * @param user_data 用户数据
 */
void protocol_set_data_callback(protocol_handle_t handle, 
                               protocol_data_callback_t callback, 
                               void* user_data);

/**
 * @brief 注册发送结果回调
 * @param handle 协议句柄
 * @param callback 发送结果回调函数
 * @param user_data 用户数据
 */
void protocol_set_send_result_callback(protocol_handle_t handle, 
                                      protocol_send_result_callback_t callback, 
                                      void* user_data);

/**
 * @brief 检查连接状态
 * @param handle 协议句柄
 * @return true已连接，false未连接
 */
bool protocol_is_connected(protocol_handle_t handle);

/**
 * @brief 获取版本信息
 * @return 版本字符串
 */
const char* protocol_get_version(void);

#ifdef __cplusplus
}
#endif

#endif /* PROTOCOL104_H */
EOF
}

# 构建函数
build_protocol() {
    local protocol=$1
    local version=$2
    
    print_info "🚀 开始构建 $protocol 协议的 $version 版本..."
    print_info "═══════════════════════════════════════════════════════════════"
    
    # 检查协议目录是否存在
    if [ ! -d "core/$protocol" ]; then
        print_error "协议目录不存在: core/$protocol"
        return 1
    fi
    
    # 生成版本信息
    print_info "📝 步骤 1/6: 生成版本信息"
    print_info "───────────────────────────────────────────────────────────────"
    if ! ./scripts/generate_version.sh "$version" "$protocol"; then
        print_error "❌ 版本信息生成失败"
        return 1
    fi
    print_info "   ✅ 版本信息已生成"
    
    # 确保输出目录存在 - 统一输出结构
    print_info "📁 步骤 2/6: 创建输出目录结构"
    print_info "───────────────────────────────────────────────────────────────"
    mkdir -p "output/lib"
    mkdir -p "output/include"
    print_info "   ✅ 输出目录已创建"
    
    # 构建通用模块
    print_info "🔧 步骤 3/6: 构建通用模块 (common/)"
    print_info "───────────────────────────────────────────────────────────────"
    cd "common" || return 1
    print_info "   🧹 清理通用模块构建文件..."
    make clean > /dev/null 2>&1 || true
    
    print_info "   ⚙️  编译通用模块..."
    if ! make all > /dev/null 2>&1; then
        print_error "   ❌ 通用模块构建失败"
        cd "$PROJECT_ROOT" || exit
        return 1
    fi
    print_info "   ✅ 通用模块构建成功"
    cd "$PROJECT_ROOT" || exit
    
    # 构建应用模块
    print_info "🔧 步骤 4/6: 构建应用模块 (core/$protocol/)"
    print_info "───────────────────────────────────────────────────────────────"
    cd "core/$protocol" || return 1
    print_info "   🧹 清理应用模块构建文件..."
    make clean > /dev/null 2>&1 || true
    
    # 对于test版本，使用debug模式构建应用模块
    local build_target="$version"
    if [ "$version" = "test" ]; then
        build_target="debug"
        print_info "   🔄 测试版本使用debug模式构建"
    fi
    
    print_info "   ⚙️  编译应用模块 (目标: $build_target)..."
    if ! make "$build_target" > /dev/null 2>&1; then
        print_error "   ❌ 应用模块构建失败"
        cd "$PROJECT_ROOT" || exit
        return 1
    else
        print_info "   ✅ 应用模块构建成功"
        cd "$PROJECT_ROOT" || exit
    fi
    
    # 整理输出文件
    print_info "📦 步骤 5/6: 整理输出文件"
    print_info "───────────────────────────────────────────────────────────────"
    organize_output_files "$protocol" "$version"
    print_info "   ✅ 输出文件整理完成"
    
    # 整理输出到104子目录
    print_info "📁 整理输出到协议目录..."
    organize_output "$protocol"
    print_info "   ✅ 协议目录整理完成"
    
    # 构建应用程序
    print_info "📱 步骤 6/7: 构建应用程序 (app/)"
    print_info "───────────────────────────────────────────────────────────────"
    if [ -d "app" ]; then
        cd "app" || return 1
        print_info "   🧹 清理应用程序构建文件..."
        make clean > /dev/null 2>&1 || true
        
        print_info "   ⚙️  编译应用程序..."
        if ! make all > /dev/null 2>&1; then
            print_error "   ❌ 应用程序构建失败"
            cd "$PROJECT_ROOT" || exit
            return 1
        else
            print_info "   ✅ 应用程序构建成功"
            cd "$PROJECT_ROOT" || exit
        fi
        
        # 安装应用程序到输出目录
        print_info "   📦 安装应用程序到输出目录..."
        cd "app" || return 1
        make install > /dev/null 2>&1
        cd "$PROJECT_ROOT" || exit
        print_info "   ✅ 应用程序安装完成"
    else
        print_info "   ⚠️  app目录不存在，跳过应用程序构建"
    fi
    
    # 构建测试程序（独立编译，不依赖外部库文件）
    if [ "$version" = "test" ]; then
        print_info "🧪 步骤 7/7: 构建测试程序"
        print_info "───────────────────────────────────────────────────────────────"
        
        # 构建统一单元测试
        print_info "   🔧 构建统一单元测试 (test/unit/core/$protocol/)..."
        
        # 编译统一单元测试程序
        print_info "      ⚙️  编译统一单元测试程序..."
        local test_sources="test/unit/core/$protocol/unified_unit_test.c"
        test_sources="$test_sources test/unit/core/$protocol/common/utils/test_common.c"
        test_sources="$test_sources test/unit/core/$protocol/api/test_protocol_interface.c"
        test_sources="$test_sources test/unit/core/$protocol/control/connection/test_protocol_connection.c"
        test_sources="$test_sources test/unit/core/$protocol/control/statemachine/test_protocol_statemachine.c"
        test_sources="$test_sources test/unit/core/$protocol/data/telemetry/test_telemetry_data.c"
        test_sources="$test_sources test/unit/core/$protocol/protocol/asdu/test_asdu_parser.c"
        test_sources="$test_sources test/unit/core/$protocol/protocol/apdu/test_packet_parsing.c"
        
        # 编译参数
        local test_cflags="-Wall -Wextra -std=c99 -g -O0"
        local test_includes="-I../../../../core/$protocol/common/include"
        test_includes="$test_includes -I../../../../core/$protocol/control/connection/include"
        test_includes="$test_includes -I../../../../core/$protocol/control/sequence/include"
        test_includes="$test_includes -I../../../../core/$protocol/control/statemachine/include"
        test_includes="$test_includes -I../../../../core/$protocol/control/timeout/include"
        test_includes="$test_includes -I../../../../core/$protocol/control/validator/include"
        test_includes="$test_includes -I../../../../core/$protocol/data/analog/include"
        test_includes="$test_includes -I../../../../core/$protocol/data/control/include"
        test_includes="$test_includes -I../../../../core/$protocol/data/energy/include"
        test_includes="$test_includes -I../../../../core/$protocol/data/pulse/include"
        test_includes="$test_includes -I../../../../core/$protocol/data/system/include"
        test_includes="$test_includes -I../../../../core/$protocol/data/telemetry/include"
        test_includes="$test_includes -I../../../../core/$protocol/parameter/include"
        test_includes="$test_includes -I../../../../core/$protocol/protocol/apdu/include"
        test_includes="$test_includes -I../../../../core/$protocol/protocol/asdu/include"
        test_includes="$test_includes -I../../../../core/$protocol/transfer/file/include"
        test_includes="$test_includes -I../../../../core/$protocol/transfer/upgrade/include"
        test_includes="$test_includes -I../../../../core/$protocol/transport/include"
        test_includes="$test_includes -I../../../../common/utils/include"
        test_includes="$test_includes -I../../../../common/include"
        test_includes="$test_includes -I../../../../common/version/include"
        test_includes="$test_includes -I../../../../common/logs/include"
        
        # 编译统一单元测试（包含日志库）
        if gcc $test_cflags $test_includes -Icommon/logs/include -o "test/unit/core/$protocol/unified_unit_test" $test_sources common/logs/src/logger.c 2>/dev/null; then
            print_info "      ✅ 统一单元测试程序构建成功"
            chmod +x "test/unit/core/$protocol/unified_unit_test"
        else
            print_error "      ❌ 统一单元测试程序构建失败"
            # 不提前退出，继续执行后续步骤
        fi
        
        # 构建业务测试
        print_info "   🔧 构建业务测试 (test/business/)..."
        cd "test/business" || return 1
        print_info "      🧹 清理业务测试构建文件..."
        make clean > /dev/null 2>&1 || true
        
        print_info "      ⚙️  编译业务测试程序..."
        if ! make all; then
            print_error "      ❌ 业务测试构建失败"
            cd "$PROJECT_ROOT" || exit
            # 不提前退出，继续执行后续步骤
        else
            print_info "      ✅ 业务测试构建成功"
            
            # 安装业务测试到输出目录
            print_info "      📦 安装业务测试到输出目录..."
            if ! make install; then
                print_error "      ❌ 业务测试安装失败"
            else
                print_info "      ✅ 业务测试安装完成"
            fi
            
            cd "$PROJECT_ROOT" || exit
        fi
        
        echo ""
        print_info "   📊 测试构建统计:"
        print_info "      🧪 单元测试: 已构建"
        print_info "      🔧 业务测试: 已构建"
    else
        print_info "ℹ️  非测试版本，跳过测试程序构建"
    fi
    
    # 如果是测试版本，整理测试文件
    if [ "$version" = "test" ]; then
        print_info "📁 整理测试文件..."
        organize_test_files "$protocol"
        print_info "   ✅ 测试文件整理完成"
    fi
    
    echo ""
    print_success "🎉 构建完成！"
    print_info "═══════════════════════════════════════════════════════════════"
    echo ""
    
    # 显示最终输出信息
    print_info "📋 最终输出:"
    echo "  📁 静态库: output/$protocol/protocol/$protocol-*-$version.a"
    echo "  📁 头文件: output/$protocol/protocol/$protocol-*-$version.h"
    
    # 检查app产物是否存在
    if [ -f "output/$protocol/${protocol}_protocol_app" ]; then
        echo "  📱 应用程序: output/$protocol/${protocol}_protocol_app"
    fi
    
    # 如果是测试版本，显示测试文件信息
    if [ "$version" = "test" ]; then
        echo "  📁 单元测试: output/$protocol/test/unit/"
        echo "  📄 统一单元测试程序: output/$protocol/test/unit/unified_unit_test"
        
        # 检查业务测试文件是否存在
        if [ -f "output/$protocol/test/business/telecontrol/test_telecontrol" ]; then
            echo "  📁 业务测试: output/$protocol/test/business/"
            echo "  📄 遥控业务测试: output/$protocol/test/business/telecontrol/test_telecontrol"
        fi
        
        # 检查其他业务测试
        for business_type in telemetry telepulse teleadjustment; do
            if [ -f "output/$protocol/test/business/$business_type/test_$business_type" ]; then
                echo "  📄 ${business_type}业务测试: output/$protocol/test/business/$business_type/test_$business_type"
            fi
        done
    fi
    
    echo ""
    print_info "💡 用户使用方式:"
    echo "  #include \"$protocol-*-$version.h\""
    echo "  gcc -I./output/$protocol/protocol -L./output/$protocol/protocol -l:$protocol-*-$version.a your_program.c"
    
    # 如果app产物存在，显示app运行方式
    if [ -f "output/$protocol/${protocol}_protocol_app" ]; then
        echo ""
        print_info "📱 应用程序运行方式:"
        echo "  cd output/$protocol"
        echo "  ./${protocol}_protocol_app                    # 运行104协议应用程序"
    fi
    
    # 如果是测试版本，显示测试运行方式
    if [ "$version" = "test" ]; then
        echo ""
        print_info "🧪 测试运行方式:"
        echo "  # 运行统一单元测试:"
        echo "  cd output/$protocol/test/unit"
        echo "  ./unified_unit_test                    # 运行所有测试"
        echo "  ./unified_unit_test --list             # 显示测试模块列表"
        echo "  ./unified_unit_test --module 1         # 运行指定模块测试"
        
        # 检查业务测试文件是否存在
        if [ -f "output/$protocol/test/business/telecontrol/test_telecontrol" ]; then
            echo ""
            echo "  # 运行业务测试:"
            echo "  cd output/$protocol/test/business/telecontrol"
            echo "  ./test_telecontrol         # 遥控业务测试"
        fi
        
        # 检查其他业务测试
        for business_type in telemetry telepulse teleadjustment; do
            if [ -f "output/$protocol/test/business/$business_type/test_$business_type" ]; then
                echo "  cd ../$business_type"
                echo "  ./test_$business_type      # ${business_type}业务测试"
            fi
        done
    fi
}

# 整理测试文件
organize_test_files() {
    local protocol=$1
    
    # 确保在项目根目录
    cd "$PROJECT_ROOT" || return 1
    
    # 创建测试输出目录
    print_info "📁 创建测试输出目录..."
    mkdir -p "output/$protocol/test/unit"
    mkdir -p "output/$protocol/test/business/telecontrol"
    mkdir -p "output/$protocol/test/business/telemetry"
    mkdir -p "output/$protocol/test/business/telepulse"
    mkdir -p "output/$protocol/test/business/teleadjustment"
    
    # 复制主测试可执行文件
    if [ -f "test/unit/core/$protocol/test_main" ]; then
        print_info "📄 复制主测试程序..."
        cp "test/unit/core/$protocol/test_main" "output/$protocol/test/unit/"
        
        # 设置可执行权限
        chmod +x "output/$protocol/test/unit/test_main"
    fi
    
    # 复制统一单元测试可执行文件
    if [ -f "test/unit/core/$protocol/unified_unit_test" ]; then
        print_info "📄 复制统一单元测试程序..."
        cp "test/unit/core/$protocol/unified_unit_test" "output/$protocol/test/unit/"
        
        # 设置可执行权限
        chmod +x "output/$protocol/test/unit/unified_unit_test"
    fi
    
    # 检查业务测试可执行文件（文件已直接编译到正确位置）
    print_info "📄 检查业务测试程序..."
    
    # 检查遥控业务测试
    if [ -f "output/$protocol/test/business/telecontrol/test_telecontrol" ]; then
        chmod +x "output/$protocol/test/business/telecontrol/test_telecontrol"
        print_info "   ✅ 遥控业务测试: output/$protocol/test/business/telecontrol/test_telecontrol"
    else
        print_warning "   ⚠️  遥控业务测试文件不存在"
    fi
    
    # 检查其他业务测试（如果存在）
    for business_type in telemetry telepulse teleadjustment; do
        if [ -f "output/$protocol/test/business/$business_type/test_$business_type" ]; then
            chmod +x "output/$protocol/test/business/$business_type/test_$business_type"
            print_info "   ✅ ${business_type}业务测试: output/$protocol/test/business/$business_type/test_$business_type"
        fi
    done
    
    print_success "测试文件整理完成"
}

# 整理输出到协议子目录
organize_output() {
    local protocol=$1
    
    # 确保在项目根目录
    cd "$PROJECT_ROOT" || return 1
    
    # 创建协议子目录
    print_info "📁 创建${protocol}输出目录..."
    mkdir -p "output/$protocol/protocol"
    
    # 移动静态库到protocol目录，使用app标识+时间戳+版本命名
    local lib_file=$(find "output/$protocol/lib" -name "libprotocol104_*_debug.a" | head -1)
    if [ -n "$lib_file" ]; then
        # 提取时间戳和版本信息
        local timestamp=$(echo "$lib_file" | sed 's/.*libprotocol104_\([0-9]*\)_debug\.a/\1/')
        local final_lib_name="${protocol}-${timestamp}-test.a"
        mv "$lib_file" "output/$protocol/protocol/$final_lib_name"
        print_info "✅ 静态库已移动到: output/$protocol/protocol/$final_lib_name"
    else
        print_warning "静态库不存在: output/$protocol/lib/libprotocol104_*_debug.a"
    fi
    
    # 移动头文件到protocol目录，使用app标识+时间戳+版本命名
    if [ -f "output/$protocol/include/protocol104.h" ]; then
        local final_header_name="${protocol}-${timestamp}-test.h"
        mv "output/$protocol/include/protocol104.h" "output/$protocol/protocol/$final_header_name"
        print_info "✅ 头文件已移动到: output/$protocol/protocol/$final_header_name"
    fi
    
    # 清理不需要的文件和目录，只保留静态库和头文件
    print_info "🧹 清理不需要的文件..."
    rm -rf "output/obj" "output/transport" "output/lib" "output/include" "output/$protocol/include" "output/$protocol/lib" "output/$protocol/bin" "output/$protocol/obj" 2>/dev/null || true
    
    # 确保测试文件不被删除（如果是测试版本）
    if [ -d "output/$protocol/test" ]; then
        print_info "✅ 保留测试文件: output/$protocol/test/"
    fi
}

# 清理函数
clean_build() {
    print_info "🧹 开始清理构建文件..."
    echo ""
    
    local cleaned_count=0
    
    # 清理通用模块
    if [ -d "common" ]; then
        print_info "📁 清理通用模块 (common/)..."
        cd "common" && make clean > /dev/null 2>&1 || true
        cd "$PROJECT_ROOT" || exit
        print_info "   ✅ 通用模块构建文件已清理"
        ((cleaned_count++))
    fi
    
    # 清理所有协议模块
    if [ -d "app" ]; then
        print_info "📁 清理协议模块 (core/)..."
        for protocol_dir in core/*/; do
            if [ -d "$protocol_dir" ] && [ -f "$protocol_dir/Makefile" ]; then
                local protocol_name=$(basename "$protocol_dir")
                print_info "   🔧 清理协议: $protocol_name"
                cd "$protocol_dir" && make clean > /dev/null 2>&1 || true
                cd "$PROJECT_ROOT" || exit
            fi
        done
        print_info "   ✅ 所有协议模块构建文件已清理"
        ((cleaned_count++))
    fi
    
    # 清理测试目录中的可执行文件
    if [ -d "test" ]; then
        print_info "🧪 清理测试可执行文件 (test/)..."
        local test_files=$(find test -name "test_*" -type f -executable 2>/dev/null | wc -l)
        if [ "$test_files" -gt 0 ]; then
            find test -name "test_*" -type f -executable -delete 2>/dev/null || true
            print_info "   🗑️  删除了 $test_files 个测试可执行文件"
        else
            print_info "   ℹ️  没有找到测试可执行文件"
        fi
        ((cleaned_count++))
    fi
    
    # 清理输出目录和临时文件
    if [ -d "output" ]; then
        print_info "📦 清理输出目录 (output/)..."
        local output_size=$(du -sh output 2>/dev/null | cut -f1 || echo "未知")
        rm -rf output
        print_info "   🗑️  删除了输出目录 (大小: $output_size)"
        ((cleaned_count++))
    else
        print_info "📦 输出目录 (output/) 不存在，跳过清理"
    fi
    
    # 清理临时文件
    print_info "🧽 清理临时文件..."
    local temp_files=0
    
    # 清理 .o 文件
    local obj_files=$(find . -name "*.o" -type f 2>/dev/null | wc -l)
    if [ "$obj_files" -gt 0 ]; then
        find . -name "*.o" -type f -delete 2>/dev/null || true
        print_info "   🗑️  删除了 $obj_files 个目标文件 (.o)"
        ((temp_files++))
    fi
    
    # 清理 .d 文件
    local dep_files=$(find . -name "*.d" -type f 2>/dev/null | wc -l)
    if [ "$dep_files" -gt 0 ]; then
        find . -name "*.d" -type f -delete 2>/dev/null || true
        print_info "   🗑️  删除了 $dep_files 个依赖文件 (.d)"
        ((temp_files++))
    fi
    
    # 清理 .a 文件（除了在 output 目录中的）
    local lib_files=$(find . -name "*.a" -type f 2>/dev/null | wc -l)
    if [ "$lib_files" -gt 0 ]; then
        find . -name "*.a" -type f -delete 2>/dev/null || true
        print_info "   🗑️  删除了 $lib_files 个静态库文件 (.a)"
        ((temp_files++))
    fi
    
    if [ "$temp_files" -eq 0 ]; then
        print_info "   ℹ️  没有找到临时文件"
    fi
    ((cleaned_count++))
    
    echo ""
    print_info "📊 清理统计:"
    print_info "   🗂️  清理的目录/模块: $cleaned_count"
    print_info "   🗑️  清理的临时文件类型: $temp_files"
    echo ""
    print_success "✨ 清理完成！所有构建文件和临时文件已删除"
}

# 从配置文件加载配置
load_config() {
    log_function_entry "load_config"
    
    local config_file="config/project.conf"
    print_debug "配置文件路径: $config_file"
    
    if [ ! -f "$config_file" ]; then
        print_error "配置文件不存在: $config_file"
        print_info "请先运行: ./build.sh set"
        log_function_exit "load_config" 1
        exit 1
    fi
    
    print_info "加载配置文件: $config_file"
    print_debug "开始读取配置文件内容..."
    
    # 初始化变量
    PROTOCOL=""
    BUILD_TYPE=""
    VERSION=""
    VERSION_MAJOR=""
    VERSION_MINOR=""
    VERSION_PATCH=""
    
    # 读取配置
    local line_count=0
    while IFS='=' read -r key value; do
        line_count=$((line_count + 1))
        print_debug "读取第${line_count}行: $key=$value"
        
        case $key in
            PROTOCOL)
                PROTOCOL="$value"
                print_debug "设置 PROTOCOL: $value"
                ;;
            BUILD_TYPE)
                BUILD_TYPE="$value"
                print_debug "设置 BUILD_TYPE: $value"
                ;;
            VERSION)
                VERSION="$value"
                print_debug "设置 VERSION: $value"
                ;;
            VERSION_MAJOR)
                VERSION_MAJOR="$value"
                print_debug "设置 VERSION_MAJOR: $value"
                ;;
            VERSION_MINOR)
                VERSION_MINOR="$value"
                print_debug "设置 VERSION_MINOR: $value"
                ;;
            VERSION_PATCH)
                VERSION_PATCH="$value"
                print_debug "设置 VERSION_PATCH: $value"
                ;;
            *)
                print_debug "忽略未知配置项: $key"
                ;;
        esac
    done < "$config_file"
    
    print_debug "配置文件读取完成，共读取 $line_count 行"
    
    # 构建版本字符串
    VERSION_STRING="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
    print_debug "构建版本字符串: $VERSION_STRING"
    
    print_info "配置加载完成:"
    print_info "  协议: $PROTOCOL"
    print_info "  构建类型: $BUILD_TYPE"
    print_info "  版本: $VERSION"
    print_info "  版本字符串: $VERSION_STRING"
    
    log_function_exit "load_config" 0
}

# 设置配置
set_config() {
    print_info "启动交互式配置选择器..."
    
    # 首先选择协议
    protocol_selection_menu
    
    print_success "配置设置完成"
}

# 协议选择配置菜单
protocol_selection_menu() {
    CURRENT_SELECTION=0
    show_menu "选择协议类型" "104协议" "退出"
    handle_input
    local choice=$?
    
    case $choice in
        0)  # 104协议
            protocol_104_config_menu
            ;;
        1)  # 退出
            print_info "配置取消"
            exit 0
            ;;
        -1)  # 退出
            exit 0
            ;;
    esac
}

# 104协议配置菜单
protocol_104_config_menu() {
    CURRENT_SELECTION=0
    show_menu "104协议配置选项" "全量编译" "只编译协议" "返回上级"
    handle_input
    local choice=$?
    
    case $choice in
        0)  # 全量编译
            protocol_104_version_config "full"
            ;;
        1)  # 只编译协议
            protocol_104_version_config "protocol"
            ;;
        2)  # 返回上级
            protocol_selection_menu
            ;;
        -1)  # 退出
            exit 0
            ;;
    esac
}

# 104协议版本配置
protocol_104_version_config() {
    local build_type="$1"
    CURRENT_SELECTION=0
    show_menu "选择构建版本" "测试版本" "调试版本" "正式版本" "返回上级"
    handle_input
    local choice=$?
    
    case $choice in
        0)  # 测试版本
            create_config_file "104" "$build_type" "test"
            ;;
        1)  # 调试版本
            create_config_file "104" "$build_type" "debug"
            ;;
        2)  # 正式版本
            create_config_file "104" "$build_type" "release"
            ;;
        3)  # 返回上级
            protocol_104_config_menu
            ;;
        -1)  # 退出
            exit 0
            ;;
    esac
}

# 执行构建
do_build() {
    log_function_entry "do_build"
    
    # 检查配置文件是否存在
    log_file_operation "检查" "config/project.conf"
    if [ ! -f "config/project.conf" ]; then
        print_error "配置文件不存在: config/project.conf"
        print_info "请先运行: ./build.sh set"
        log_function_exit "do_build" 1
        exit 1
    fi
    print_debug "配置文件存在: config/project.conf"
    
    # 使用生成的配置文件
    print_debug "开始加载配置文件..."
    load_config
    print_debug "配置文件加载完成"
    
    # 验证配置参数
    print_debug "验证配置参数..."
    print_debug "  PROTOCOL: '$PROTOCOL'"
    print_debug "  VERSION: '$VERSION'"
    print_debug "  BUILD_TYPE: '$BUILD_TYPE'"
    
    if [ -z "$PROTOCOL" ] || [ -z "$VERSION" ] || [ -z "$BUILD_TYPE" ]; then
        print_error "配置文件缺少必需参数"
        print_info "请先运行: ./build.sh set"
        log_function_exit "do_build" 1
        exit 1
    fi
    print_debug "配置参数验证通过"
    
    print_info "开始构建..."
    print_info "  协议: $PROTOCOL"
    print_info "  构建类型: $BUILD_TYPE"
    print_info "  版本: $VERSION"
    print_debug "当前日志级别: $(get_log_level_name)"
    
    case "$BUILD_TYPE" in
        "full")
            print_info "执行全量编译..."
            print_debug "调用 build_protocol 函数"
            build_protocol "$PROTOCOL" "$VERSION"
            ;;
        "protocol")
            print_info "只编译协议..."
            print_debug "调用 build_protocol 函数"
            build_protocol "$PROTOCOL" "$VERSION"
            ;;
        *)
            print_error "未知的构建类型: $BUILD_TYPE"
            log_function_exit "do_build" 1
            exit 1
            ;;
    esac
    
    print_success "构建完成"
    print_debug "构建流程执行完毕"
    log_function_exit "do_build" 0
}

# 主函数
main() {
    log_function_entry "main" "$*"
    
    # 检查是否有日志级别参数
    if [ "${1:-}" = "debug" ] || [ "${1:-}" = "trace" ]; then
        set_log_level "$1"
        shift
    fi
    
    print_debug "脚本启动参数: $*"
    print_debug "当前工作目录: $(pwd)"
    print_debug "脚本路径: $0"
    print_debug "项目根目录: $PROJECT_ROOT"
    
    # 解析命令行参数
    case "${1:-}" in
        set)
            print_debug "执行 set 命令"
            set_config
            ;;
        build)
            # 构建模式：直接执行构建
            print_info "构建模式：直接执行构建"
            print_debug "执行 build 命令"
            # 检查配置文件
            if [ ! -f "config/project.conf" ]; then
                print_error "配置文件不存在: config/project.conf"
                print_info "请先运行: ./build.sh set"
                log_function_exit "main" 1
                exit 1
            fi
            load_config
            do_build
            ;;
        interactive)
            # 交互式菜单模式
            print_info "启动交互式菜单模式"
            print_debug "执行 interactive 命令"
            # 检查配置文件
            if [ ! -f "config/project.conf" ]; then
                print_warning "配置文件不存在，将启动配置选择器"
                set_config
            else
                load_config
            fi
            main_menu
            ;;
        clean)
            print_debug "执行 clean 命令"
            clean_build
            ;;
        -h|--help|help)
            print_debug "执行 help 命令"
            show_help
            ;;
        "")
            # 默认行为：先设置配置，然后构建
            print_info "默认模式：设置配置并构建"
            print_debug "执行默认行为"
            set_config
            do_build
            ;;
        *)
            print_error "未知命令: $1"
            show_help
            log_function_exit "main" 1
            exit 1
            ;;
    esac
    
    # 显示日志统计
    show_log_stats
    log_function_exit "main" 0
}

# 运行主函数
main "$@"
